package cn.lili.modules.payment.kit;

import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.ClientTypeEnum;
import cn.lili.common.enums.DictCodeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.SpringContextUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.utils.SysDictUtils;
import cn.lili.common.vo.ResultMessage;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.member.entity.dos.Member;
import cn.lili.modules.member.entity.dos.Partner;
import cn.lili.modules.member.mapper.PartnerMapper;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.vo.OrderVO;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.payment.entity.enums.CashierEnum;
import cn.lili.modules.payment.entity.enums.PaymentClientEnum;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
import cn.lili.modules.payment.kit.dto.PayParam;
import cn.lili.modules.payment.kit.params.CashierExecute;
import cn.lili.modules.payment.kit.params.dto.CashierParam;
import cn.lili.modules.store.entity.dos.Store;
import cn.lili.modules.store.service.StoreService;
import cn.lili.modules.system.entity.dos.Setting;
import cn.lili.modules.system.entity.dto.OrderSetting;
import cn.lili.modules.system.entity.dto.payment.PaymentSupportSetting;
import cn.lili.modules.system.entity.dto.payment.dto.PaymentSupportItem;
import cn.lili.modules.system.entity.enums.SettingEnum;
import cn.lili.modules.system.service.SettingService;
import cn.lili.modules.wallet.entity.enums.WalletOwnerEnum;
import cn.lili.modules.wallet.service.MemberWalletService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 收银台工具
 *
 * @author Chopper
 * @since 2020-12-19 09:25
 */
@Component
@Slf4j
public class CashierSupport {
	/**
	 * 收银台
	 */
	@Autowired
	private List<CashierExecute> cashierExecuteList;
	/**
	 * 预存款
	 */
	@Autowired
	private MemberWalletService memberWalletService;
	/**
	 * 配置
	 */
	@Autowired
	private SettingService settingService;

	@Autowired
	private GoodsSkuService getGoodsSkuService;

	@Autowired
	private StoreService storeService;

	@Autowired
	private OrderService orderService;

	@Autowired
	private PartnerMapper partnerMapper;

	/**
	 * 支付
	 *
	 * @param paymentMethodEnum
	 *            支付渠道枚举
	 * @param paymentClientEnum
	 *            支付方式枚举
	 * @return 支付消息
	 */
	public ResultMessage<Object> buyerPayment(PaymentMethodEnum paymentMethodEnum, PaymentClientEnum paymentClientEnum,
			HttpServletRequest request, HttpServletResponse response, PayParam payParam, String paymentPassword) {
		if (paymentClientEnum == null || paymentMethodEnum == null) {
			throw new ServiceException(ResultCode.PAY_NOT_SUPPORT);
		}
		// OrderVO order = null;
		// if ("ORDER".equals(payParam.getOrderType())){
		// order = orderService.getBySn(payParam.getSn());
		// }else if ("TRADE".equals(payParam.getOrderType())){
		// order = orderService.getOrderInfoByTradeSn(payParam.getSn());
		// }

		if (UserContext.getCurrentUser() == null) {
			throw new ServiceException(ResultCode.USER_NOT_LOGIN);
		}
		// 通过memberid查询会员支付密码dai
		Member member = orderService.getMemberInfo(UserContext.getCurrentUser().getId());
		if (member == null) {
			throw new ServiceException("会员信息查询失败");
		}
		if (!"WECHAT".equals(paymentMethodEnum.name())) {
			// 设置免密后跳过支付密码验证
			if (0 == member.getNoSecret()) {
				if (!new BCryptPasswordEncoder().matches(paymentPassword, member.getPaymentPassword())) {
					throw new ServiceException(ResultCode.PAY_PASSWORD_ERROR);
				}
			}

		}
		// 获取支付插件
		Payment payment = (Payment) SpringContextUtil.getBean(paymentMethodEnum.getPlugin());
		log.info("支付请求：客户端：{},支付类型：{},请求：{}", paymentClientEnum.name(), paymentMethodEnum.name(), payParam.toString());

		// 支付方式调用
		switch (paymentClientEnum) {
			case H5 :
				return payment.h5pay(request, response, payParam);
			case APP :
				return payment.appPay(request, payParam);
			case JSAPI :
				return payment.jsApiPay(request, payParam);
			case NATIVE :
				return payment.nativePay(request, payParam);
			case MP :
				return payment.mpPay(request, payParam);
			case TRANSFER :
				return payment.transferPay(request, payParam);
			default :
				return null;
		}
	}

	/**
	 * 支付
	 *
	 * @param paymentMethodEnum
	 *            支付渠道枚举
	 * @param paymentClientEnum
	 *            支付方式枚举
	 * @return 支付消息
	 */
	public ResultMessage<Object> payment(PaymentMethodEnum paymentMethodEnum, PaymentClientEnum paymentClientEnum,
			HttpServletRequest request, HttpServletResponse response, PayParam payParam) {
		if (paymentClientEnum == null || paymentMethodEnum == null) {
			throw new ServiceException(ResultCode.PAY_NOT_SUPPORT);
		}
		// 获取支付插件
		Payment payment = (Payment) SpringContextUtil.getBean(paymentMethodEnum.getPlugin());
		log.info("支付请求：客户端：{},支付类型：{},请求：{}", paymentClientEnum.name(), paymentMethodEnum.name(), payParam.toString());

		// 支付方式调用
		switch (paymentClientEnum) {
			case H5 :
				return payment.h5pay(request, response, payParam);
			case APP :
				return payment.appPay(request, payParam);
			case JSAPI :
				return payment.jsApiPay(request, payParam);
			case NATIVE :
				return payment.nativePay(request, payParam);
			case MP :
				return payment.mpPay(request, payParam);
			default :
				return null;
		}
	}

	/**
	 * 支付 支持的支付方式
	 *
	 * @param client
	 *            客户端类型
	 * @return 支持的支付方式
	 */
	public List<String> support(String client) {

		ClientTypeEnum clientTypeEnum;
		try {
			clientTypeEnum = ClientTypeEnum.valueOf(client);
		} catch (IllegalArgumentException e) {
			throw new ServiceException(ResultCode.PAY_CLIENT_TYPE_ERROR);
		}
		// 支付方式 循环获取
		Setting setting = settingService.get(SettingEnum.PAYMENT_SUPPORT.name());
		PaymentSupportSetting paymentSupportSetting = JSONUtil.toBean(setting.getSettingValue(),
				PaymentSupportSetting.class);
		for (PaymentSupportItem paymentSupportItem : paymentSupportSetting.getPaymentSupportItems()) {
			if (paymentSupportItem.getClient().equals(clientTypeEnum.name())) {
				return paymentSupportItem.getSupports();
			}
		}
		throw new ServiceException(ResultCode.PAY_NOT_SUPPORT);
	}

	/**
	 * 支付回调
	 *
	 * @param paymentMethodEnum
	 *            支付渠道枚举
	 * @return 回调消息
	 */
	public void callback(PaymentMethodEnum paymentMethodEnum, HttpServletRequest request) {

		log.info("支付回调：支付类型：{}", paymentMethodEnum.name());

		// 获取支付插件
		Payment payment = (Payment) SpringContextUtil.getBean(paymentMethodEnum.getPlugin());
		payment.callBack(request);
	}

	/**
	 * 支付通知
	 *
	 * @param paymentMethodEnum
	 *            支付渠道
	 */
	public void notify(PaymentMethodEnum paymentMethodEnum, HttpServletRequest request) {

		log.info("支付异步通知：支付类型：{}", paymentMethodEnum.name());

		// 获取支付插件
		Payment payment = (Payment) SpringContextUtil.getBean(paymentMethodEnum.getPlugin());
		payment.notify(request);
	}

	/**
	 * 获取收银台参数
	 *
	 * @param payParam
	 *            支付请求参数
	 * @return 收银台参数
	 */
	public CashierParam cashierParam(PayParam payParam) {
		for (CashierExecute paramInterface : cashierExecuteList) {
			CashierParam cashierParam = paramInterface.getPaymentParams(payParam);
			// 如果为空，则表示收银台参数初始化不匹配，继续匹配下一条
			if (cashierParam == null) {
				continue;
			}
			// 如果订单不需要付款，则抛出异常，直接返回
			if (cashierParam.getPrice() < 0) {
				throw new ServiceException(ResultCode.PAY_UN_WANTED);
			}
			if (!payParam.getOrderType().equals(CashierEnum.DUES.name())
					&& !payParam.getOrderType().equals(CashierEnum.MEMBER.name())
					&& !payParam.getOrderType().equals(CashierEnum.RECHARGE.name())
					&& !payParam.getOrderType().equals(CashierEnum.SELLER.name())) {
				Double commission = 0D;
				Double price = cashierParam.getPrice();
				OrderVO bySn = orderService.getBySn(cashierParam.getOrderSns());
				cashierParam.setGoodsPrice(
						CurrencyUtil.sub(price, bySn.getFreightPrice() != null ? bySn.getFreightPrice() : 0D));
				cashierParam.setFreightPrice(bySn.getFreightPrice());
				// if("WECHAT_MP2".equals(payParam.getClientType())) {
				// if (!payParam.getOrderType().equals(CashierEnum.RECHARGE.name())) {
				Store store = storeService.getById(bySn.getStoreId());
				Double fee = Double.parseDouble(SysDictUtils.getValueString(DictCodeEnum.ORDER_FEE.dictCode()));
				if (store != null && fee != null && fee.compareTo(0D) > 0) {
					// commission = CurrencyUtil.mul(commission,cashierParam.getPrice());
					commission = CurrencyUtil.mul(fee, bySn.getGoodsPrice());
				} else if (store != null) {
					Setting setting = settingService.get(SettingEnum.ORDER_SETTING.toString());
					Gson gson = new Gson();
					commission = CurrencyUtil.div(Double.valueOf(SysDictUtils.getValueString("order_fee")), 100);
					// commission = CurrencyUtil.mul(commission,cashierParam.getPrice());
					commission = CurrencyUtil.mul(commission, bySn.getGoodsPrice());
				}
				// }

				// Setting setting = settingService.get(SettingEnum.ORDER_SETTING.toString());
				// Gson gson = new Gson();
				// Map map = new HashMap();
				// map = gson.fromJson(setting.getSettingValue(), map.getClass());
				// commission =
				// CurrencyUtil.div(Double.parseDouble(map.get("b2bFee").toString()),100);
				// //B2B流水佣金
				// commission = CurrencyUtil.mul(commission,cashierParam.getPrice());
				// }
				cashierParam.setCommission(commission);
				// price = CurrencyUtil.add(cashierParam.getPrice(), commission);

				// 设置商品会员价
				cashierParam.setMemberPrice(getGoodsSkuService.countMemberPrice(price));
				if (bySn != null && "SELF_PICK_UP".equals(bySn.getDeliveryMethod())) {
					// order.setFlowPrice(order.getGoodsPrice());
					cashierParam.setMemberPrice(getGoodsSkuService.countMemberPrice(cashierParam.getGoodsPrice()));
				}

			}
			cashierParam.setSupport(support(payParam.getClientType()));
			String memberId = UserContext.getCurrentUser() != null
					? UserContext.getCurrentUser().getId()
					: payParam.getMembeId();

			cashierParam.setWalletValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.RECHARGE.name()).getMemberWallet());
			cashierParam.setWalletSaleValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.SALE.name()).getMemberWallet());
			// 根据合伙人身份获取钱包余额
			QueryWrapper<Partner> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("member_id", memberId);
			queryWrapper.eq("partner_state", 0);
			queryWrapper.orderByDesc("end_time");
			queryWrapper.last("limit 1");
			Partner partner = partnerMapper.selectOne(queryWrapper);
			if (partner != null && 4 == partner.getPartnerType()) {
				cashierParam.setWalletPromoteHyValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE_HY.name()).getMemberWallet());
				cashierParam.setWalletPromoteFwValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE_FW.name()).getMemberWallet());
			} else {
				cashierParam.setWalletPromoteValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE.name()).getMemberWallet());
			}
			OrderSetting orderSetting = JSONUtil
					.toBean(settingService.get(SettingEnum.ORDER_SETTING.name()).getSettingValue(), OrderSetting.class);
			Integer minute = orderSetting.getAutoCancel();
			cashierParam.setAutoCancel(cashierParam.getCreateTime().getTime() + minute * 1000 * 60);
			return cashierParam;
		}
		log.error("错误的支付请求:{}", payParam.toString());
		throw new ServiceException(ResultCode.PAY_CASHIER_ERROR);
	}

	public CashierParam cashierParamNative(PayParam payParam) {
		for (CashierExecute paramInterface : cashierExecuteList) {
			CashierParam cashierParam = paramInterface.getPaymentParams(payParam);
			// 如果为空，则表示收银台参数初始化不匹配，继续匹配下一条
			if (cashierParam == null) {
				continue;
			}
			// 如果订单不需要付款，则抛出异常，直接返回
			if (cashierParam.getPrice() < 0) {
				throw new ServiceException(ResultCode.PAY_UN_WANTED);
			}
			cashierParam.setSupport(support(payParam.getClientType()));

			// String owner = payParam.getOwner();
			// cashierParam.setWalletValue(memberWalletService.getMemberWallet(UserContext.getCurrentUser().getId(),
			// owner).getMemberWallet());
			OrderSetting orderSetting = JSONUtil
					.toBean(settingService.get(SettingEnum.ORDER_SETTING.name()).getSettingValue(), OrderSetting.class);

			String memberId = UserContext.getCurrentUser() != null
					? UserContext.getCurrentUser().getId()
					: payParam.getMembeId();
			cashierParam.setWalletValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.RECHARGE.name()).getMemberWallet());
			cashierParam.setWalletSaleValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.SALE.name()).getMemberWallet());
			// 根据合伙人身份获取钱包余额
			QueryWrapper<Partner> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("member_id", memberId);
			queryWrapper.eq("partner_state", 0);
			queryWrapper.orderByDesc("end_time");
			queryWrapper.last("limit 1");
			Partner partner = partnerMapper.selectOne(queryWrapper);
			if (partner != null && 4 == partner.getPartnerType()) {
				cashierParam.setWalletPromoteHyValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE_HY.name()).getMemberWallet());
				cashierParam.setWalletPromoteFwValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE_FW.name()).getMemberWallet());
			} else {
				cashierParam.setWalletPromoteValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE.name()).getMemberWallet());
			}
			Integer minute = orderSetting.getAutoCancel();
			cashierParam.setAutoCancel(cashierParam.getCreateTime().getTime() + minute * 1000 * 60);
			return cashierParam;
		}
		log.error("错误的支付请求:{}", payParam.toString());
		throw new ServiceException(ResultCode.PAY_CASHIER_ERROR);
	}

	public CashierParam cashierParamTransfer(PayParam payParam) {
		for (CashierExecute paramInterface : cashierExecuteList) {
			CashierParam cashierParam = paramInterface.getPaymentTransfer(payParam);
			// 如果为空，则表示收银台参数初始化不匹配，继续匹配下一条
			if (cashierParam == null) {
				continue;
			}
			// 如果订单不需要付款，则抛出异常，直接返回
			if (cashierParam.getPrice() < 0) {
				throw new ServiceException(ResultCode.PAY_UN_WANTED);
			}
			cashierParam.setSupport(support(payParam.getClientType()));

			String memberId = UserContext.getCurrentUser() != null
					? UserContext.getCurrentUser().getId()
					: payParam.getMembeId();
			cashierParam.setWalletValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.RECHARGE.name()).getMemberWallet());
			cashierParam.setWalletSaleValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.SALE.name()).getMemberWallet());
			// String owner = payParam.getOwner();
			// cashierParam.setWalletValue(
			// memberWalletService.getMemberWallet(UserContext.getCurrentUser().getId(),
			// owner).getMemberWallet());
			OrderSetting orderSetting = JSONUtil
					.toBean(settingService.get(SettingEnum.ORDER_SETTING.name()).getSettingValue(), OrderSetting.class);
			Integer minute = orderSetting.getAutoCancel();
			cashierParam.setAutoCancel(cashierParam.getCreateTime().getTime() + minute * 1000 * 60);
			return cashierParam;
		}
		log.error("错误的支付请求:{}", payParam.toString());
		throw new ServiceException(ResultCode.PAY_CASHIER_ERROR);
	}

	public CashierParam cashierParamsNative(PayParam payParam) {
		for (CashierExecute paramInterface : cashierExecuteList) {
			// CashierParam cashierParam = paramInterface.getPaymentParams(payParam);
			CashierParam cashierParam = paramInterface.getPaymentNative(payParam);
			// 如果为空，则表示收银台参数初始化不匹配，继续匹配下一条
			if (cashierParam == null) {
				continue;
			}
			cashierParam.setSupport(support(payParam.getClientType()));
			String memberId = UserContext.getCurrentUser() != null
					? UserContext.getCurrentUser().getId()
					: payParam.getMembeId();

			cashierParam.setWalletValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.RECHARGE.name()).getMemberWallet());
			cashierParam.setWalletSaleValue(
					memberWalletService.getMemberWallet(memberId, WalletOwnerEnum.SALE.name()).getMemberWallet());
			// 根据合伙人身份获取钱包余额
			QueryWrapper<Partner> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("member_id", memberId);
			queryWrapper.eq("partner_state", 0);
			queryWrapper.orderByDesc("end_time");
			queryWrapper.last("limit 1");
			Partner partner = partnerMapper.selectOne(queryWrapper);
			if (partner != null && 4 == partner.getPartnerType()) {
				cashierParam.setWalletPromoteHyValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE_HY.name()).getMemberWallet());
				cashierParam.setWalletPromoteFwValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE_FW.name()).getMemberWallet());
			} else {
				cashierParam.setWalletPromoteValue(memberWalletService
						.getMemberWallet(memberId, WalletOwnerEnum.PROMOTE.name()).getMemberWallet());
			}
			OrderSetting orderSetting = JSONUtil
					.toBean(settingService.get(SettingEnum.ORDER_SETTING.name()).getSettingValue(), OrderSetting.class);
			Integer minute = orderSetting.getAutoCancel();
			cashierParam.setAutoCancel(cashierParam.getCreateTime().getTime() + minute * 1000 * 60);
			return cashierParam;
		}
		log.error("错误的支付请求:{}", payParam.toString());
		throw new ServiceException(ResultCode.PAY_CASHIER_ERROR);
	}

	/**
	 * 支付结果
	 *
	 * @param payParam
	 * @return
	 */
	public Boolean paymentResult(PayParam payParam) {
		for (CashierExecute cashierExecute : cashierExecuteList) {
			if (cashierExecute.cashierEnum().name().equals(payParam.getOrderType())) {
				return cashierExecute.paymentResult(payParam);
			}
		}
		return false;
	}
}
